package com.dimples.dd.apidoc.config;

import com.dimples.dd.apidoc.properties.ApiDocInfoProperties;
import com.dimples.dd.common.constant.DDConstant;
import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Contact;
import io.swagger.v3.oas.models.info.Info;
import io.swagger.v3.oas.models.info.License;
import io.swagger.v3.oas.models.security.OAuthFlow;
import io.swagger.v3.oas.models.security.OAuthFlows;
import io.swagger.v3.oas.models.security.SecurityRequirement;
import io.swagger.v3.oas.models.security.SecurityScheme;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;

/**
 * OpenAPI 配置类
 * <p>
 * 基于 OpenAPI 3.0 规范 + SpringDoc 实现 + knife4j 增强
 *
 * @author zhongyj <1126834403@qq.com><br/>
 * @date 2024/5/23
 */
@Slf4j
@Configuration
@EnableConfigurationProperties(ApiDocInfoProperties.class)
@ConditionalOnClass({OpenAPI.class})
@ConditionalOnProperty(value = "springdoc.api-docs.enable", havingValue = "true", matchIfMissing = true)
public class DDOpenApiConfig {

    /**
     * OAuth2 认证 endpoint
     */
    @Value("${spring.security.oauth2.authorizationserver.token-uri}")
    private String tokenUrl;

    /**
     * OpenAPI 配置（元信息、安全协议）
     */
    @Bean
    public OpenAPI apiInfo(ApiDocInfoProperties apiDocInfoProperties) {
        log.info(DDConstant.CONFIG_LOG, "Open Knife4j Config");

        return new OpenAPI()
                .components(buildComponents())
                // 接口全局添加 Authorization 参数
                .addSecurityItem(new SecurityRequirement().addList(HttpHeaders.AUTHORIZATION))
                // 接口文档信息(不重要)
                .info(buildInfo(apiDocInfoProperties));
    }

    private Components buildComponents() {
        return new Components()
                .addSecuritySchemes(HttpHeaders.AUTHORIZATION,
                        new SecurityScheme()
                                // OAuth2 授权模式
                                .type(SecurityScheme.Type.OAUTH2)
                                .name(HttpHeaders.AUTHORIZATION)
                                .flows(new OAuthFlows()
                                        .password(
                                                new OAuthFlow()
                                                        .tokenUrl(tokenUrl)
                                                        .refreshUrl(tokenUrl)
                                        )
                                )
                                // 安全模式使用Bearer令牌（即JWT）
                                .in(SecurityScheme.In.HEADER)
                                .scheme("Bearer")
                                .bearerFormat("JWT")
                );
    }
    
    private Info buildInfo(ApiDocInfoProperties apiDocInfoProperties) {
        String description = String.format("<div style='font-size:%spx;color:%s;'>%s</div>",
                apiDocInfoProperties.getDescriptionFontSize(), apiDocInfoProperties.getDescriptionColor(), apiDocInfoProperties.getDescription());

        return new Info()
                .title(apiDocInfoProperties.getTitle())
                .version(apiDocInfoProperties.getVersion())
                .description(description)
                .contact(new Contact()
                        .name(apiDocInfoProperties.getName())
                        .url(apiDocInfoProperties.getUrl())
                        .email(apiDocInfoProperties.getEmail())
                )
                .license(new License().name(apiDocInfoProperties.getLicenseName())
                        .url(apiDocInfoProperties.getLicenseUrl())
                );
    }

}
